#include <iostream>
#include <cstring>
using namespace std;

typedef long long ll; //这里注意，状态表示的累加是可能爆int的

const int N = 15;     //行列的数目最多是11
const int M = 1 << N; //状态数量最多是1<<11

int n, m;   //获取棋盘大小，n行m列
ll f[N][M]; //状态表示
bool st[M]; //对两个状态的或起来以后是否合法，既或上以后是否有连续空间的为奇数，那么就是false

int main()
{
    freopen("cin.txt", "r", stdin);
    while (cin >> n >> m, n || m) //输入方式
    {
        //预处理阶段，首先将st数组进行初始化
        memset(st, true, sizeof st);     //先默认全部合法
        for (int i = 0; i < 1 << n; ++i) //穷举所有状态，其实应该是两个状态的或
        {
            int cnt = 0;                //记录某一连续0区间中0的数量
            for (int j = 0; j < n; ++j) //遍历全部列，既用位运算来解析当前状态
            {
                if (i >> j & 1) //解析出状态，含义是状态i的第j+1列，如果是1
                {
                    if (cnt & 1) //如果是奇数，类似于cnt%2
                    {
                        st[i] = false; //如果是奇数，那么就直接不合法
                        break;         //不合法了，也没必要继续遍历当前状态下去了
                    }
                    else //偶数就直接归零就行
                        cnt = 0;
                }
                else //如果解析出的还是0的，那么下一位
                    ++cnt;
            }
            if (cnt & 1) //注意一下，最后还得确认一下最后一块连续的区间是不是也是奇数
                st[i] = false;
        }
        memset(f, 0, sizeof f);                    //初始化状态表示方程嘛，毕竟是多次输入，前面的可能造成影响的（主要是后面直接是+=甚至没有初始化）
        f[0][0] = 1;                               //因为f[0][0]无法被递推，所以要先预处理。对于f[0][k!=0]，都是不合理的，毕竟第一列没人戳它
        for (int i = 1; i <= m; ++i)               //遍历每一列，把每一列戳出去，最后到m列其实主要是为了获取f[m][0]，其他的状态都会戳出去一个，戳出去就就违法了
            for (int j = 0; j < 1 << n; ++j)       //遍历所有当前可能的状态状态
                for (int k = 0; k < 1 << n; ++k)   //遍历所有前面可能的状态
                    if ((j & k) == 0 && st[j | k]) //前面的!(j&k)是防止前面被戳的地方还戳出去了。后面st[j|k]就是经常说的，要求既没有被戳也没有戳别人的空地方一定要能放下竖着的
                        f[i][j] += f[i - 1][k];    //注意，这里完全不用担心f[0][k]的情况，就算加上了也是0，因为压根戳出不出来
        cout << f[m][0] << endl;                   //最后一列本来就是一个都不能戳出来的
    }
    return 0;
}